var wuyb = {};
wuyb.controller;
wuyb.menu;

// Imports goog.bind from closure.
wuyb.bindNative_ = function(fn, selfObj, var_args) {
  return /** @type {!Function} */
  (fn.call.apply(fn.bind, arguments));
};

wuyb.bindJs_ = function(fn, selfObj, var_args) {
  if (!fn) {
    throw new Error();
  }

  if (arguments.length > 2) {
    var boundArgs = Array.prototype.slice.call(arguments, 2);
    return function() {
      // Prepend the bound arguments to the current arguments.
      var newArgs = Array.prototype.slice.call(arguments);
      Array.prototype.unshift.apply(newArgs, boundArgs);
      return fn.apply(selfObj, newArgs);
    };

  } else {
    return function() {
      return fn.apply(selfObj, arguments);
    };
  }
};

wuyb.bind = function(fn, selfObj, var_args) {
  // TODO(nicksantos): narrow the type signature.
  if (Function.prototype.bind &&
  // NOTE(nicksantos): Somebody pulled base.js into the default
  // Chrome extension environment. This means that for Chrome extensions,
  // they get the implementation of Function.prototype.bind that
  // calls goog.bind instead of the native one. Even worse, we don't want
  // to introduce a circular dependency between goog.bind and
  // Function.prototype.bind, so we have to hack this to make sure it
  // works correctly.
  Function.prototype.bind.toString().indexOf('native code') != -1) {
    wuyb.bind = wuyb.bindNative_;
  } else {
    wuyb.bind = wuyb.bindJs_;
  }
  return wuyb.bind.apply(null, arguments);
};

/**
 * Set iframe to design on mode.
 */
wuyb.setDesignModeAndRTL = function(frameId) {
  var frame = document.getElementById(frameId);
  var doc;
  if (navigator.appName == "Microsoft Internet Explorer")
    doc = window.frames[frameId].document;
  else
    doc = (frame.document || frame.contentDocument || frame.contentWindow.document);
  doc.designMode = "On";
  doc.body.setAttribute('dir', 'rtl');
};

/**
 * Set iframe to design on mode.
 */
wuyb.setDesignMode = function(frameId) {
  var frame = document.getElementById(frameId);
  var doc;
  if (navigator.appName == "Microsoft Internet Explorer")
    doc = window.frames[frameId].document;
  else
    doc = (frame.document || frame.contentDocument || frame.contentWindow.document);
  doc.designMode = "On";
};


/**
 * Actions with focus event. In older version of IE, there is not
 * addEventListener method, using attachElement can't pass the correct element
 * which capture the event. so we pass the optinal element.
 * 
 * @param {Event}
 *          e The event.
 */
wuyb.onFocus = function(e) {
  wuyb.menu.bindElement(this.frameElement || this);
  wuyb.menu.reposition(this.frameElement || this,
      google.elements.inputtools.PositionType.BOTTOM_RIGHT);
};

wuyb.changeInputTool = function(e) {
  var inputTool = this.value;
  wuyb.controller.activateInputTool(inputTool);
};

/**
 * Create input tools type selection menus.
 * 
 * @param {string}
 *          containerId The container element id.
 */
wuyb.createMenu = function(containerId) {
  var select = document.createElement('select');
  for (key in google.elements.inputtools.InputToolCode) {
    var option = document.createElement('option');
    option.value = google.elements.inputtools.InputToolCode[key];
    option.title = key;
    option.appendChild(document.createTextNode(key));
    select.appendChild(option);
  }
  document.getElementById(containerId).appendChild(select);
  select.onchange = wuyb.changeInputTool;
};

/**
 * Create input tools widget.
 * 
 * @param {Array.
 *          <string>} The input boxs' id;
 * @param {Object.
 *          <string, string>} The widget config.
 */
wuyb.createWidget = function(inputBox, config) {
  if (!inputBox || inputBox.length == 0)
    return;
  wuyb.menu = wuyb.controller.showControl(config);
  for ( var i = 0; i < inputBox.length; i++) {
    var elem = document.getElementById(inputBox[i]);
    var target = elem;
    if (elem.tagName && elem.tagName.toUpperCase() == 'IFRAME') {
      target = elem.contentWindow;
    }

    if (elem.addEventListener) {
      target.addEventListener('focus', wuyb.onFocus, false);
    } else {
	// In older version of IE, there is not addEventListener method,
    // using attachElement can't pass the correct element
    // which capture the event. so we pass the optinal element.
    var onFocusInner = wuyb.bind(wuyb.onFocus, elem);
      target.attachEvent('onfocus', onFocusInner, false);
    }
  }
  // Sets the first input box as default input box.
  wuyb.menu.bindElement(inputBox[0]);
};

/**
 * @param {Array.
 *          <string>} The input boxs' id; Set up after finishing load.
 */
wuyb.setUp = function(inputBox) {
  wuyb.controller = new google.elements.inputtools.InputToolsController();
  var allInputTools = [];
  for ( var key in google.elements.inputtools.InputToolCode) {
    allInputTools.push(google.elements.inputtools.InputToolCode[key]);
  }
  wuyb.controller.addInputTools(allInputTools);
  wuyb.controller.addPageElements(inputBox);
};